package com.sse.deployer;

import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.TitledBorder;

import com.sse.sensor.utils.EventoUtil;
import com.sse.util.LectorProperties;

public class Principal {

	private JFrame frmSseExperimento;
	private JTextField textSCentralIp;
	private JTextArea textAreaSalida;

	private Process procesoBalanceador;
	private boolean leerSalidaBalanceador = false;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		try {
			UIManager
					.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
		} catch (Throwable e) {
			e.printStackTrace();
		}
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Principal window = new Principal();
					window.frmSseExperimento.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public Principal() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frmSseExperimento = new JFrame();
		frmSseExperimento.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				cerrandoAplicacion();
			}
		});
		frmSseExperimento.setTitle("SSE - Experimento 3 - Deployer");
		frmSseExperimento.setBounds(100, 100, 813, 602);
		frmSseExperimento.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frmSseExperimento.getContentPane().setLayout(null);

		JLabel lblNewLabel_1 = new JLabel("SSE - Experimento 3");
		lblNewLabel_1.setFont(new Font("Tahoma", Font.BOLD, 14));
		lblNewLabel_1.setBounds(43, 30, 165, 14);
		frmSseExperimento.getContentPane().add(lblNewLabel_1);

		JPanel panel_1 = new JPanel();
		panel_1.setBorder(new TitledBorder(null, "SALIDA",
				TitledBorder.LEADING, TitledBorder.TOP, null, null));
		panel_1.setBounds(10, 285, 764, 268);
		frmSseExperimento.getContentPane().add(panel_1);
		panel_1.setLayout(null);

		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(10, 23, 744, 200);
		panel_1.add(scrollPane);

		textAreaSalida = new JTextArea();
		textAreaSalida.setFont(new Font("Tahoma", Font.PLAIN, 11));
		scrollPane.setViewportView(textAreaSalida);

		JButton btnLimpiar = new JButton("Limpiar");
		btnLimpiar.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				limpiarTextArea();
			}
		});
		btnLimpiar.setBounds(10, 234, 89, 23);
		panel_1.add(btnLimpiar);

		JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
		tabbedPane.setBounds(10, 74, 764, 194);
		frmSseExperimento.getContentPane().add(tabbedPane);

		JPanel panel_6 = new JPanel();
		tabbedPane.addTab("Casa", null, panel_6, null);
		panel_6.setLayout(null);

		JPanel panel_2 = new JPanel();
		panel_2.setBounds(543, 11, 201, 145);
		panel_6.add(panel_2);
		panel_2.setBorder(new TitledBorder(null, "Eventos",
				TitledBorder.LEADING, TitledBorder.TOP, null, null));
		panel_2.setLayout(null);

		comboBoxTipoEvento = new JComboBox();
		comboBoxTipoEvento.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				Object source = e.getSource();

				if (source == comboBoxTipoEvento) {
					Object selectedItem = ((JComboBox) source)
							.getSelectedItem();
					if (selectedItem == null) {
						return;
					}

					String opcion = selectedItem.toString();

					ComboBoxModel model = null;

					if (opcion.equals("HUMO")) {
						model = new DefaultComboBoxModel(
								EventoUtil.eventosSensorHumo.values().toArray());
					} else if (opcion.equals("PUERTA")) {
						model = new DefaultComboBoxModel(
								EventoUtil.eventosSensorPuerta.values()
										.toArray());
					} else if (opcion.equals("ANTENA")) {
						model = new DefaultComboBoxModel(
								EventoUtil.eventosSensorAntena.values()
										.toArray());
					} else if (opcion.equals("INGRESO")) {
						model = new DefaultComboBoxModel(
								EventoUtil.eventosSensorIngreso.values()
										.toArray());
					} else if (opcion.equals("MOVIMIENTO")) {
						model = new DefaultComboBoxModel(
								EventoUtil.eventosSensorMovimiento.values()
										.toArray());
					} else if (opcion.equals("VENTANA")) {
						model = new DefaultComboBoxModel(
								EventoUtil.eventosSensorVentana.values()
										.toArray());
					}

					if (model != null) {
						comboBoxEventos.setModel(model);
					}
				}
			}
		});
		// comboBoxTipoEvento.setModel(new DefaultComboBoxModel(new String[]
		// {"HUMO", "PUERTA", "VENTANA", "MOVIMIENTO", "RFID"}));
		comboBoxTipoEvento.setModel(new DefaultComboBoxModel(
				EventoUtil.tiposSensores));
		comboBoxTipoEvento.setEditable(true);
		comboBoxTipoEvento.setBounds(66, 25, 118, 20);
		comboBoxTipoEvento.setSelectedIndex(-1);
		panel_2.add(comboBoxTipoEvento);

		comboBoxEventos = new JComboBox();

		comboBoxEventos.setBounds(66, 62, 118, 20);
		panel_2.add(comboBoxEventos);

		JButton btnLanzar = new JButton("Lanzar");
		btnLanzar.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				botonLanzarEventoPulsado();
			}
		});
		btnLanzar.setBounds(54, 93, 89, 23);
		panel_2.add(btnLanzar);

		JLabel lblNewLabel_2 = new JLabel("Sensor:");
		lblNewLabel_2.setHorizontalAlignment(SwingConstants.RIGHT);
		lblNewLabel_2.setBounds(10, 28, 46, 14);
		panel_2.add(lblNewLabel_2);

		JLabel lblNewLabel_3 = new JLabel("Evento:");
		lblNewLabel_3.setHorizontalAlignment(SwingConstants.RIGHT);
		lblNewLabel_3.setBounds(10, 65, 46, 14);
		panel_2.add(lblNewLabel_3);

		JPanel panel = new JPanel();
		panel.setBounds(10, 11, 214, 145);
		panel_6.add(panel);
		panel.setBorder(new TitledBorder(null, "Sistema Central / Balanceador",
				TitledBorder.LEADING, TitledBorder.TOP, null, null));
		panel.setLayout(null);

		JLabel lblNewLabel = new JLabel("IP:");
		lblNewLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		lblNewLabel.setBounds(22, 37, 46, 14);
		panel.add(lblNewLabel);

		textSCentralIp = new JTextField();
		// textSCentralIp.setText("localhost");
		textSCentralIp.setText(LectorProperties
				.leerPropiedad("IpBalanceadorCarga"));

		textSCentralIp.setBounds(75, 34, 121, 20);
		panel.add(textSCentralIp);
		textSCentralIp.setColumns(10);

		JButton btnConectar = new JButton("Conectar");
		btnConectar.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				botonConectarPulsado();
			}
		});
		btnConectar.setBounds(10, 99, 89, 23);
		panel.add(btnConectar);

		JLabel lblPuerto = new JLabel("Puerto:");
		lblPuerto.setHorizontalAlignment(SwingConstants.RIGHT);
		lblPuerto.setBounds(22, 67, 46, 14);
		panel.add(lblPuerto);

		textPuerto = new JTextField();
		// textPuerto.setText("5000");
		textPuerto.setText(LectorProperties
				.leerPropiedad("PuertoLecturaTramasBC"));
		textPuerto.setBounds(75, 61, 121, 20);
		panel.add(textPuerto);
		textPuerto.setColumns(10);

		JButton btnNewButton = new JButton("Cerrar");
		btnNewButton.setBounds(115, 99, 89, 23);
		panel.add(btnNewButton);

		JPanel panel_3 = new JPanel();
		panel_3.setBounds(234, 11, 295, 145);
		panel_6.add(panel_3);
		panel_3.setBorder(new TitledBorder(null, "Base de Datos",
				TitledBorder.LEADING, TitledBorder.TOP, null, null));
		panel_3.setLayout(null);

		JLabel lblIp = new JLabel("URL:");
		lblIp.setHorizontalAlignment(SwingConstants.RIGHT);
		lblIp.setBounds(10, 32, 57, 14);
		panel_3.add(lblIp);

		textJDBCUrl = new JTextField();
		// textJDBCUrl.setText("jdbc:postgresql://localhost:5432/ash");
		textJDBCUrl.setText(LectorProperties.leerPropiedad("FuenteBD"));
		textJDBCUrl.setBounds(77, 29, 208, 20);
		panel_3.add(textJDBCUrl);
		textJDBCUrl.setColumns(10);

		JLabel lblUsuario = new JLabel("Usuario:");
		lblUsuario.setHorizontalAlignment(SwingConstants.RIGHT);
		lblUsuario.setBounds(10, 57, 57, 14);
		panel_3.add(lblUsuario);

		JLabel lblPassword = new JLabel("Password:");
		lblPassword.setHorizontalAlignment(SwingConstants.RIGHT);
		lblPassword.setBounds(10, 82, 57, 14);
		panel_3.add(lblPassword);

		textUsuario = new JTextField();
		// textUsuario.setText("postgresql");
		textUsuario.setText(LectorProperties.leerPropiedad("UsuarioBD"));
		textUsuario.setBounds(77, 54, 114, 20);
		panel_3.add(textUsuario);
		textUsuario.setColumns(10);

		textPassword = new JPasswordField();
		textPassword.setEchoChar('*');
		textPassword.setBounds(77, 79, 114, 20);
		panel_3.add(textPassword);
		textPassword.setColumns(10);
		textPassword.setText(LectorProperties.leerPropiedad("PasswordBD"));

		JLabel lblIdCasa = new JLabel("ID Casa:");
		lblIdCasa.setHorizontalAlignment(SwingConstants.RIGHT);
		lblIdCasa.setBounds(10, 107, 57, 14);
		panel_3.add(lblIdCasa);

		textIdCasa = new JTextField();
		textIdCasa.setText("2");
		textIdCasa.setBounds(77, 104, 114, 20);
		panel_3.add(textIdCasa);
		textIdCasa.setColumns(10);

		JPanel panel_5 = new JPanel();
		tabbedPane.addTab("Balanceador", null, panel_5, null);
		panel_5.setLayout(null);

		JButton btnIniciar = new JButton("Iniciar");
		btnIniciar.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				iniciarBalanceador();
			}
		});
		btnIniciar.setBounds(10, 41, 89, 23);
		panel_5.add(btnIniciar);

		JButton btnDetener = new JButton("Detener");
		btnDetener.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				detenerBalanceador();
			}
		});
		btnDetener.setBounds(115, 41, 89, 23);
		panel_5.add(btnDetener);

		JPanel panel_4 = new JPanel();
		tabbedPane.addTab("Sistema Central", null, panel_4, null);

		inicializacionLocal();

	}

	protected void detenerBalanceador() {

		this.procesoBalanceador.destroy();
		leerSalidaBalanceador = false;
		agregarTexto("Finalizando Balanceador de carga. ");

	}

	protected void cerrandoAplicacion() {

		agregarTexto("Cerrando aplicacion Deployer ....");
		System.out.println("....");
		procesoBalanceador.destroy();

	}

	private void inicializacionLocal() {
		redirectSystemStreams();

	}

	/**
	 * Inicia el balanceador de cargas como un proceso aparte.
	 */
	protected void iniciarBalanceador() {

		String WORKSPACE = null;
		String JAVA_HOME = null;
		try {
			WORKSPACE = LectorProperties.leerPropiedad("workspaceLocation");
			JAVA_HOME = System.getProperty("java.home");

		} catch (Exception e) {
			agregarTexto("Revise el archivo config.properties y asegurese que exista la propiedad: 'workspaceLocation'. Tambien que su sistema tenga %JAVA_HOME%");
			return;
		}
		
		
		StringBuilder comando = new StringBuilder(JAVA_HOME)
				.append("\\bin\\javaw.exe");

		// file.encoding
		// path.separator

		final String encoding = "-Dfile.encoding=Cp1252";
		String classpathParam = "-classpath";

		StringBuilder classpath = new StringBuilder(WORKSPACE)
				.append("\\sse-experimento2-loadbalancer\\target\\classes;")
				.append(WORKSPACE).append("\\sse-experimento1-comun\\bin ");

		String className = "com.sse.lb.core.ListenerBalanceadorCarga";

		ProcessBuilder pb = new ProcessBuilder(comando.toString(), encoding,
				classpathParam, classpath.toString(), className);

		pb.redirectErrorStream(true);

		try {

			procesoBalanceador = pb.start();
			final InputStream is = procesoBalanceador.getInputStream();
			leerSalidaBalanceador = true;

			Thread t = new Thread(new Runnable() {

				@Override
				public void run() {
					InputStreamReader isr = new InputStreamReader(is);
					BufferedReader br = new BufferedReader(isr);
					String line;

					try {
						while ((line = br.readLine()) != null) {
							agregarTexto("Balanceador: " + line);
							if (!leerSalidaBalanceador) {
								agregarTexto("Finalizando lectura de salida del Balanceador. ");
							}
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			});

			t.start();

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SS");
	private JComboBox comboBoxTipoEvento;
	private JComboBox comboBoxEventos;
	private JTextField textPuerto;
	private JTextField textJDBCUrl;
	private JTextField textUsuario;
	private JPasswordField textPassword;
	private JTextField textIdCasa;

	/**
	 * Metodo que agrega una cadena de texto al textareal.
	 * 
	 * @param texto
	 */
	private void agregarTexto(String texto) {
		StringBuilder sb = new StringBuilder(textAreaSalida.getText());
		sb.append("\n");
		sb.append(sdf.format(new Date(System.currentTimeMillis())));
		sb.append(" - ");
		sb.append(texto);
		textAreaSalida.setText(sb.toString());
	}

	private void limpiarTextArea() {
		textAreaSalida.setText("");
	}

	/**
	 * MEtodo llamado cuando se pulsa el boton Conectar.
	 */
	private void botonConectarPulsado() {

		try {
			DeployerCore.getInstance().setIdCasa(textIdCasa.getText());
			DeployerCore.getInstance().setJdbcURL(textJDBCUrl.getText());
			DeployerCore.getInstance().setPassword(
					String.valueOf(textPassword.getPassword()));
			DeployerCore.getInstance().setSistemaCentralIP(
					textSCentralIp.getText());
			DeployerCore.getInstance().setUsuario(textUsuario.getText());
			DeployerCore.getInstance().setSistemaCentralPuerto(
					Integer.valueOf(textPuerto.getText()));

			String[] resultado = DeployerCore.getInstance().conectar();

			for (String s : resultado) {
				this.agregarTexto(s);
			}

		} catch (Exception e) {
			agregarTexto("Excepcion no controlada: Ex: " + e.getMessage());
		} catch (Error e) {
			agregarTexto("Error detectado:  Error: " + e.getMessage());
		} catch (Throwable e) {
			agregarTexto("Throwable detectado:  Th : " + e.getMessage());
		}

	}

	private void botonLanzarEventoPulsado() {
		// String resultado =
		// "Lanzando Evento:  "+comboBoxTipoEvento.getSelectedItem().toString()+
		// " - "+comboBoxEventos.getSelectedItem().toString();

		String sensor = comboBoxTipoEvento.getSelectedItem().toString();
		String evento = comboBoxEventos.getSelectedItem().toString();

		String resultado = DeployerCore.getInstance().lanzarEvento(sensor,
				evento);

		this.agregarTexto(resultado);
	}

	public JTextArea getTextAreaSalida() {
		return textAreaSalida;
	}

	public JComboBox getComboBoxTipoEvento() {
		return comboBoxTipoEvento;
	}

	public JComboBox getComboBoxEventos() {
		return comboBoxEventos;
	}

	private void updateTextArea(final String text) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				agregarTexto(text);
			}
		});
	}

	/**
	 * Redirige los streams de error y de salida hacia el text area.
	 */
	private void redirectSystemStreams() {
		OutputStream out = new TextAreaOutputStream();
		System.setOut(new PrintStream(out, true));
		System.setErr(new PrintStream(out, true));
	}

	private class TextAreaOutputStream extends OutputStream {

		@Override
		public void write(int b) throws IOException {
			updateTextArea(String.valueOf((char) b));
		}

		@Override
		public void write(byte[] b, int off, int len) throws IOException {
			updateTextArea(new String(b, off, len));
		}

		@Override
		public void write(byte[] b) throws IOException {
			write(b, 0, b.length);
		}

	}

}
